<template>
  <div class="w-full flex flex-col">
    <Select class="!mb-24px" v-model:value="data.transportType" :disabled="isDisable">
      <SelectOption value="DEFAULT">默认</SelectOption>
      <SelectOption value="MQTT">MQTT</SelectOption>
      <SelectOption value="COAP">CoAP</SelectOption>
      <SelectOption value="LWM2M">LWN2M</SelectOption>
      <SelectOption value="SNMP">SNMP</SelectOption>
    </Select>
    <!-- MQTT -->
    <div v-show="data.transportType === 'MQTT'">
      <BasicForm @register="registerMQTTForm">
        <template #sparkplugAttributesMetricNames>
          <InputList
            inputTitle="将SparkPlug指标储存为属性"
            placeholder="将SparkPlug指标储存为属性"
            inputTips="将作为设备属性存储的SparkPlug指标的名称。其他指标将作为设备遥测数据进行存储。"
            :initInputDataList="sparkplugAttributesMetricNames"
            @getInputDataList="getInputList"
          />
        </template>
        <template #deviceAttributesProtoSchema="{ model, field }">
          <CodeEditor v-model:value="model[field]" :mode="modeValue" />
        </template>
        <template #deviceRpcRequestProtoSchema="{ model, field }">
          <CodeEditor v-model:value="model[field]" :mode="modeValue" />
        </template>
        <template #deviceRpcResponseProtoSchema="{ model, field }">
          <CodeEditor v-model:value="model[field]" :mode="modeValue" />
        </template>
        <template #deviceTelemetryProtoSchema="{ model, field }">
          <CodeEditor v-model:value="model[field]" :mode="modeValue" />
        </template>
      </BasicForm>
    </div>
    <!-- COAP -->
    <div v-show="data.transportType === 'COAP'">
      <BasicForm @register="registerCoAPForm">
        <template #deviceAttributesProtoSchema="{ model, field }">
          <CodeEditor v-model:value="model[field]" :mode="modeValue" />
        </template>
        <template #deviceRpcRequestProtoSchema="{ model, field }">
          <CodeEditor v-model:value="model[field]" :mode="modeValue" />
        </template>
        <template #deviceRpcResponseProtoSchema="{ model, field }">
          <CodeEditor v-model:value="model[field]" :mode="modeValue" />
        </template>
        <template #deviceTelemetryProtoSchema="{ model, field }">
          <CodeEditor v-model:value="model[field]" :mode="modeValue" />
        </template>
      </BasicForm>
    </div>
    <!-- LWM2M -->
    <LWM2MTransportConfiguration
      v-if="data.transportType === 'LWM2M'"
      ref="LWM2MTransport"
      :formData="emitsValue"
      :disable="isDisable"
    />
    <!-- SNMP -->
    <div v-if="data.transportType === 'SNMP'">
      <Form :model="SNMPConfiguration" layout="vertical" ref="snmpForm">
        <Row :gutter="20">
          <Col span="12">
            <FormItem label="超时(ms)" name="timeoutMs" required>
              <InputNumber
                v-model:value="SNMPConfiguration.timeoutMs"
                :disabled="isDisable"
                :min="0"
                :parser="formatNumber"
              />
            </FormItem>
          </Col>
          <Col span="12">
            <FormItem label="重试" name="retries" required>
              <InputNumber
                v-model:value="SNMPConfiguration.retries"
                :disabled="isDisable"
                :min="0"
                :parser="formatNumber"
              />
            </FormItem>
          </Col>
        </Row>
        <p class="mb-12px">通信配置</p>
        <p
          class="text-center text-red-600 font-medium text-2xl"
          v-show="!SNMPConfiguration.communicationConfigs.length"
          >请添加通信配置</p
        >
        <div
          class="flex flex-row items-center mt-8px"
          v-for="(item, index) in SNMPConfiguration.communicationConfigs"
          :key="item.id"
        >
          <div class="border-2 border-gray-200 flex flex-row w-full">
            <!-- 左边 -->
            <div class="w-1/3 p-10px">
              <FormItem label="范围" :name="['communicationConfigs', index, 'spec']" required>
                <Select
                  class="w-full"
                  v-model:value="item.spec"
                  :disabled="isDisable"
                  :dropdownMatchSelectWidth="270"
                  placeholder="请选择"
                >
                  <SelectOption
                    v-for="option in range"
                    :key="option.value"
                    :disabled="isSelectedByOthers(option.value, item.spec)"
                    >{{ option.label }}</SelectOption
                  >
                </Select>
              </FormItem>
            </div>
            <Divider type="vertical" class="!border-l-2 !h-auto" />
            <!-- 右边 -->
            <div class="w-2/3 p-10px flex flex-col">
              <FormItem
                label="查询频率"
                :name="['communicationConfigs', index, 'queryingFrequencyMs']"
                required
                v-if="
                  item.spec === 'TELEMETRY_QUERYING' || item.spec === 'CLIENT_ATTRIBUTES_QUERYING'
                "
              >
                <InputNumber
                  v-model:value="item.queryingFrequencyMs"
                  :disabled="isDisable"
                  :min="0"
                  :parser="formatNumber"
                />
              </FormItem>

              <Row class="mb-2px">
                <Col :span="8">数据类型</Col>
                <Col :span="8">数据键</Col>
                <Col :span="8">OID</Col>
              </Row>
              <div
                v-for="(mappingItem, mappingIndex) in item.mappings"
                :key="mappingItem.id"
                class="flex flex-row items-center"
              >
                <FormItem
                  class="w-full"
                  :name="['communicationConfigs', index, 'mappings', mappingIndex, 'dataType']"
                  required
                >
                  <Select class="w-full" v-model:value="mappingItem.dataType" :disabled="isDisable">
                    <SelectOption value="STRING">字符串</SelectOption>
                    <SelectOption value="NUMERIC">整数</SelectOption>
                    <SelectOption value="BOOLEAN">布尔值</SelectOption>
                    <SelectOption value="DOUBLE">双精度小数</SelectOption>
                    <SelectOption value="JSON">JSON</SelectOption>
                  </Select>
                </FormItem>
                <FormItem
                  class="w-full"
                  :name="['communicationConfigs', index, 'mappings', mappingIndex, 'key']"
                  required
                >
                  <a-input v-model:value="mappingItem.key" :disabled="isDisable" />
                </FormItem>
                <FormItem
                  class="w-full"
                  :name="['communicationConfigs', index, 'mappings', mappingIndex, 'oid']"
                  required
                  :rules="{
                    pattern: /^\.?([0-2])((\.0)|(\.[1-9][0-9]*))*$/,
                    message: '无效OID格式',
                  }"
                >
                  <a-input v-model:value="mappingItem.oid" :disabled="isDisable" />
                </FormItem>
                <!-- 删除映射按钮 -->
                <FormItem v-show="!isDisable" :wrapperCol="{ span: 12 }" class="!w-auto">
                  <Button
                    size="large"
                    shape="circle"
                    type="text"
                    @click="deleteMapping(index, mappingIndex)"
                  >
                    <Icon :icon="ICON.X_DELETE" class="!text-3xl" />
                  </Button>
                </FormItem>
              </div>
              <!-- 添加映射按钮 -->
              <Button @click="addMapping(index)" v-if="!isDisable" class="w-150px"
                ><Icon :icon="ICON.PLUS" class="!text-2xl" />添加映射</Button
              >
            </div>
          </div>
          <!-- 删除通信配置按钮 -->
          <div v-if="!isDisable">
            <Button
              size="large"
              shape="circle"
              type="text"
              @click="deleteCommunicationConfig(index, item.spec)"
            >
              <Icon :icon="ICON.MINUS_ROUND" class="!text-3xl" />
            </Button>
          </div>
        </div>
      </Form>

      <!-- 添加通信配置按钮 -->
      <Button
        @click="addCommunicationConfig"
        v-show="selectedSpecs.length != 5 && !isDisable"
        class="mt-12px mb-24px"
        ><Icon :icon="ICON.PLUS" class="!text-2xl" />添加通信配置</Button
      >
    </div>
  </div>
</template>
<script lang="ts" setup>
  import {
    Select,
    SelectOption,
    InputNumber,
    Row,
    Col,
    Divider,
    Form,
    FormItem,
    Button,
  } from 'ant-design-vue';
  import Icon from '/@/components/Icon';
  import { ICON } from '/@/enums/iconEnum';
  import { ref, watch, onMounted, nextTick } from 'vue';
  import _ from 'lodash';
  import InputList from '/@/components/thingsborad/sharedComponents/modules/InputList.vue';
  import { BasicForm, useForm } from '/@/components/Form';
  import { CodeEditor, MODE } from '/@/components/CodeEditor';
  import LWM2MTransportConfiguration from './LWM2M/LWM2MTransportConfiguration.vue';
  import { nanoid } from 'nanoid';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { modalFormStyleSetting } from '/@/settings/thingsBoardDesign';
  import { mqttSchemas, coapSchemas } from './form.data';
  // LWM2MTransportConfiguration LWM2M传输配置组件实例
  const LWM2MTransport = ref<any>(null);
  const { createMessage } = useMessage();
  //是否只是展示
  let isDisable = ref<boolean>(false);
  //传输配值得数据
  let data = ref<Recordable>({
    transportType: 'DEFAULT',
    transportConfiguration: {},
  });
  const modeValue = ref<MODE>(MODE.JSON);
  const props = defineProps({
    formData: {
      type: Object,
    },
    disable: {
      type: Boolean,
    },
  });
  let emitsValue = ref<Recordable>({});
  //传输配置下，SNMP中通信配置范围Select的值
  let range: Recordable[] = [
    { value: 'TELEMETRY_QUERYING', label: 'Telemetry (SNMP GET)' },
    { value: 'CLIENT_ATTRIBUTES_QUERYING', label: 'Client attributes (SNMP GET)' },
    { value: 'SHARED_ATTRIBUTES_SETTING', label: 'Shared attributes (SNMP SET)' },
    {
      value: 'TO_DEVICE_RPC_REQUEST',
      label: 'To-device RPC request (SNMP GET/SET)',
    },
    {
      value: 'TO_SERVER_RPC_REQUEST',
      label: 'From-device RPC request (SNMP TRAP)',
    },
  ];

  //记录传输配置下，SNMP中通信配置范围select中已经被选中的值
  let selectedSpecs = ref<any>([]);
  //sparkplugAttributesMetricNames的默认值
  let sparkplugAttributesMetricNames = ref<any>([
    { text: 'Node Control/*' },
    { text: 'Device Control/' },
    { text: 'Properties/*' },
  ]);
  const snmpForm = ref<Recordable>({});
  let SNMPConfiguration = ref<Recordable>({
    timeoutMs: 500,
    type: 'SNMP',
    retries: 0,
    communicationConfigs: [],
  });
  //SNMP配置通信配置
  let communicationConfigsItem = ref<Recordable>({
    id: '',
    spec: null,
    queryingFrequencyMs: 5000,
    mappings: [
      {
        id: nanoid(),
        dataType: 'STRING',
        key: '',
        oid: '',
      },
    ],
  });
  //SNMP配置通信配置下的映射
  let mapping = ref<Recordable>({
    id: '',
    dataType: 'STRING',
    key: '',
    oid: '',
  });
  //MQTT表单配置
  const [
    registerMQTTForm,
    {
      getFieldsValue: getFieldsMQTTValue,
      validate: getFieldMQTTValue,
      setFieldsValue: setFieldsMQTTValue,
      setProps: setMQTTProps,
    },
  ] = useForm({
    layout: 'vertical',
    schemas: mqttSchemas,
    showActionButtonGroup: false,
    ...modalFormStyleSetting,
  });
  //COAP表单配置
  const [
    registerCoAPForm,
    { setFieldsValue: setCoapFieldsValue, setProps: setCoapProps, validate: validatecoap },
  ] = useForm({
    layout: 'vertical',
    schemas: coapSchemas,
    showActionButtonGroup: false,
    ...modalFormStyleSetting,
  });
  //添加映射
  function addMapping(i: number) {
    mapping.value.id = '';
    mapping.value.id = nanoid();
    SNMPConfiguration.value.communicationConfigs[i].mappings.push(_.cloneDeep(mapping.value));
  }
  //删除映射
  function deleteMapping(i: number, index: number) {
    SNMPConfiguration.value.communicationConfigs[i].mappings.splice(index, 1);
  }
  //添加通信配置
  function addCommunicationConfig() {
    communicationConfigsItem.value.id = '';
    communicationConfigsItem.value.id = nanoid();
    const firstMissingObject = range.find(
      (obj) => !selectedSpecs.value.some((selected) => obj.value === selected),
    );
    communicationConfigsItem.value.spec = firstMissingObject?.value;
    SNMPConfiguration.value.communicationConfigs.push(_.cloneDeep(communicationConfigsItem.value));
  }
  //删除通信配置
  function deleteCommunicationConfig(i: number, value: string) {
    selectedSpecs.value = selectedSpecs.value.filter((spec: string) => spec !== value);
    SNMPConfiguration.value.communicationConfigs.splice(i, 1);
  }
  // 判断range中的值是否被已有的通信配置中选中
  function isSelectedByOthers(optionValue: string, currentSpec: string) {
    return selectedSpecs.value.includes(optionValue) && optionValue !== currentSpec;
  }
  onMounted(async () => {
    if (emitsValue.value) {
      data.value.transportType = emitsValue.value.type;
      if (emitsValue.value.type === 'MQTT') {
        await setFieldsMQTTValue(emitsValue.value);
        sparkplugAttributesMetricNames.value = emitsValue.value.sparkplugAttributesMetricNames.map(
          (text) => ({ text }),
        );
        if (isDisable.value) {
          await setMQTTProps({ disabled: true });
        }
      }
      if (emitsValue.value.type === 'COAP') {
        if (emitsValue.value.clientSettings.psmActivityTimer) {
          let timeData = formatTime(emitsValue.value.clientSettings.psmActivityTimer);
          emitsValue.value.clientSettings.psmActivityTimer = timeData.time;
          emitsValue.value.clientSettings.timeUnitsPSM = timeData.units;
        }
        if (emitsValue.value.clientSettings.edrxCycle) {
          let timeData = formatTime(emitsValue.value.clientSettings.edrxCycle);
          emitsValue.value.clientSettings.edrxCycle = timeData.time;
          emitsValue.value.clientSettings.timeUnitsCyc = timeData.units;
        }
        if (emitsValue.value.clientSettings.pagingTransmissionWindow) {
          let timeData = formatTime(emitsValue.value.clientSettings.pagingTransmissionWindow);
          emitsValue.value.clientSettings.pagingTransmissionWindow = timeData.time;
          emitsValue.value.clientSettings.timeUnitsTra = timeData.units;
        }
        nextTick(async () => {
          await setCoapFieldsValue(emitsValue.value);
          if (isDisable.value) {
            await setCoapProps({ disabled: true });
          }
        });
      }
      if (emitsValue.value.type === 'SNMP') {
        SNMPConfiguration.value = emitsValue.value;
        selectedSpecs.value = [];
        SNMPConfiguration.value.communicationConfigs.map((item) => {
          selectedSpecs.value.push(item.spec);
        });
      }
      if (emitsValue.value.type === 'LWM2M') {
      }
    }
  });
  watch(
    () => SNMPConfiguration.value,
    (nVal) => {
      selectedSpecs.value = [];
      nVal.communicationConfigs.map((item) => {
        selectedSpecs.value.push(item.spec);
      });
      
    },
    { deep: true },
  );
  watch(
    () => props.formData,
    (nVal: Recordable) => {
      emitsValue.value = nVal;
    },
    { immediate: true, deep: true },
  );
  watch(
    () => props.disable,
    (nVal) => {
      isDisable.value = nVal;
    },
    { immediate: true },
  );
  function getInputList(data: Array<any>) {
    sparkplugAttributesMetricNames.value = data;
  }
  //保留正整数
  function formatNumber(text: string) {
    const decimalIndex = text.indexOf('.');
    return /^\d+$/.test(text) ? text : text.slice(0, decimalIndex);
  }
  //格式化时间
  function formatTime(time: number) {
    if (time >= 3600000 && time % 360000 === 0) {
      const hours = time / 3600000;
      return { time: hours, units: '小时' };
    } else if (time >= 60000 && time % 60000 === 0) {
      const minutes = time / 60000;
      return { time: minutes, units: '分钟' };
    } else if (time >= 1000 && time % 1000 === 0) {
      const seconds = time / 1000;
      return { time: seconds, units: '秒' };
    } else {
      return { time: time, units: '毫秒' };
    }
  }
  //把不同的单位都化成毫秒(时间，单位)
  function convertTime(time: number, units: string) {
    if (units === '小时') {
      return time * 3600000;
    } else if (units === '分钟') {
      return time * 60000;
    } else if (units === '秒') {
      return time * 1000;
    } else {
      return time;
    }
  }
  async function getTransportConfiguration() {
    let hasEmptyKey: Boolean = false;
    if (data.value.transportType === 'DEFAULT') {
      data.value.transportConfiguration.type = 'DEFAULT';
    } else if (data.value.transportType === 'MQTT') {
      await getFieldMQTTValue();
      data.value.transportConfiguration = getFieldsMQTTValue();
      data.value.transportConfiguration.sparkplugAttributesMetricNames =
        sparkplugAttributesMetricNames.value.map(({ text }) => text);
      data.value.transportConfiguration.type = 'MQTT';
    } else if (data.value.transportType === 'COAP') {
      data.value.transportConfiguration = await validatecoap();
      let client = data.value.transportConfiguration.clientSettings;
      if (client.powerMode === 'PSM') {
        client.psmActivityTimer = convertTime(client.psmActivityTimer, client.timeUnitsPSM);
      } else if (client.powerMode === 'E_DRX') {
        client.edrxCycle = convertTime(client.edrxCycle, client.timeUnitsCyc);
        client.pagingTransmissionWindow = convertTime(
          client.pagingTransmissionWindow,
          client.timeUnitsTra,
        );
      }
      data.value.transportConfiguration.clientSettings = client;
      data.value.transportConfiguration.type = 'COAP';
    } else if (data.value.transportType === 'SNMP') {
      try {
        await snmpForm.value.validate();
      } catch (e) {
        hasEmptyKey = true;
      }
      if (SNMPConfiguration.value.communicationConfigs.length === 0) {
        hasEmptyKey = true;
        createMessage.error('请添加通信配置');
      }
      if (hasEmptyKey === true) {
        createMessage.error('值不能为空');
        return;
      }
      data.value.transportConfiguration = SNMPConfiguration.value;
      data.value.transportConfiguration.type = 'SNMP';
    } else if (data.value.transportType === 'LWM2M') {
      data.value.transportConfiguration = await LWM2MTransport.value.getLWM2MTransportData();
      if (!data.value.transportConfiguration) {
        return;
      }
      data.value.transportConfiguration.type = 'LWM2M';
    }
    if (hasEmptyKey === true) {
      return;
    }
    return data.value.transportConfiguration;
  }
  defineExpose({
    getTransportConfiguration,
  });
</script>
<style lang="less" scoped>
  .ant-btn {
    display: flex;
    align-items: center;
    justify-content: center;
  }
</style>
